<template>
  <section ref="tinymceBox" class="tinymce-box" :class="{disabled}">
    <div :id="tinymceId"></div>
    <el-button class="tips" type="text" v-show="loading" :loading="loading">图片上传中</el-button>
    <div class="limit" ref="limit" v-if="maxLength">{{ currentLength }}/{{ maxLength }}</div>
    <input type="file" ref="file" @change="handleChange" accept="image/*" style="display: none"/>
    <div class="placeholder" ref="placeholder" v-show="!currentLength">{{ placeholder }}</div>
  </section>
</template>

<script>
import plugins from './plugins';
import toolbar from './toolbar';
import {checkImg} from '../utils';

export default {
  name: 'tinymce',
  components: {},
  props: {
    value: {
      type: String,
      default: ''
    },
    size: {
      type: Number,
      default: 5
    },
    menubar: {
      type: [Boolean, String],
      default: false
    },
    toolbar: {
      type: [Array, String]
    },
    plugins: {
      type: [Array, String]
    },
    height: {
      type: Number,
      default: 360
    },
    disabled: {
      type: Boolean,
      default: false
    },
    maxLength: {
      type: Number
    },
    placeholder: {
      type: String,
      default: '请输入...'
    },
    config: {
      type: Object
    }
  },
  data() {
    return {
      initFlag: false,
      loading: false,
      OSS_URL: process.env.VUE_APP_OSS_URL,
      visible: false,
      tinymceId: 'vue-tinymce-' + +new Date(),
      uploadConfig: this.config || this.$getGlobalConfig('upload'),
      currentLength: 0,
      topPartHeight: 0
    };
  },
  watch: {
    disabled() {
      this.setDisabled();
    },
    value(val) {
      if (!this.initFlag) {
        this.initFlag = true;
        this.$nextTick(() => this.resetContent(val || ''));
      }
    }
  },
  computed: {
    tinymce() {
      return window.tinymce.get(this.tinymceId);
    },
    getToolbar() {
      return this.toolbar || this.$getGlobalConfig('tinymce').toolbar || toolbar;
    },
    getPlugins() {
      return this.plugins || this.$getGlobalConfig('tinymce').plugins || plugins;
    }
  },
  beforeDestroy() {
    this.destroyTinymce();
  },
  mounted() {
    this.initTinymce();
  },
  methods: {
    setDisabled() {
      this.$nextTick(() => {
        let body = this.tinymce.getBody();
        if (body) body.setAttribute('contenteditable', !this.disabled);
      });
    },
    getWordLength() {
      if (!this.tinymce) return 0;
      let content = this.tinymce.getContent();
      let div = document.createElement('div');
      div.innerHTML = content;
      let currentLength = 0;
      let text = div.innerText;
      let imgList = div.querySelectorAll('img');
      let videoList = div.querySelectorAll('video');
      [].forEach.call(imgList, (img) => {
        let {src = ''} = img;
        currentLength += src.length;
      });
      [].forEach.call(videoList, (img) => {
        let {src = ''} = img;
        currentLength += src.length;
      });
      currentLength += text.length;
      return currentLength;
    },
    checkWordLength() {
      return this.getWordLength() <= this.maxLength;
    },
    resetContent(value) {
      // if(!this.checkWordLength(this.tinymce)) return;
      this.tinymce.setContent(value || '');
      this.tinymce.selection.select(this.tinymce.getBody(), true);
      this.tinymce.selection.collapse(false);
      this.currentLength = this.getWordLength();
    },
    selectImg(imgList) {
      imgList.forEach(v => {
        this.tinymce.insertContent(this.getImg(v));
      });
    },
    getImg(url) {
      return `<img class="wscnph" style="max-width: 100%" src="${this.OSS_URL + url}" />`;
    },
    checkImg(file) {
      return checkImg(file, this.uploadConfig.size || this.size);
    },
    upload(data) {
      return new Promise((resolve, reject) => {
        let xhr = new XMLHttpRequest();
        let {headers, action} = this.uploadConfig;
        xhr.onreadystatechange = function () {
          if (xhr.readyState === 4) {
            let {status, response} = xhr;
            if (status === 200) {
              resolve(JSON.parse(response));
            } else {
              reject(response);
            }
          }
        };
        xhr.open('post', action);
        if (headers) {
          for (let key in headers) {
            xhr.setRequestHeader(key, headers[key]);
          }
        }
        xhr.send(data);
      });
    },
    uploadImg(file) {
      this.loading = true;
      let fd = new FormData();
      fd.set('file', file);
      // compressImg({file,maxWidth:1024});
      this.upload(fd).then(res => {
        this.tinymce.insertContent(this.getImg(res.data));
        this.loading = false;
      })
        .catch(() => {
          this.loading = false;
          this.$message.error('图片上传失败');
        });
    },
    handleChange(e) {
      let [file] = e.target.files;
      this.uploadImg(file);
      e.target.value = '';
    },
    initTinymce() {
      window.tinymce.init({
        language: 'zh_CN',
        selector: `#${this.tinymceId}`,
        height: this.height,
        body_class: 'panel-body ',
        object_resizing: false,
        menubar: this.menubar,
        toolbar: this.getToolbar,
        plugins: this.getPlugins,
        end_container_on_empty_block: true,
        powerpaste_word_import: 'clean',
        code_dialog_height: 450,
        code_dialog_width: 1000,
        advlist_bullet_styles: 'square',
        advlist_number_styles: 'default',
        default_link_target: '_blank',
        fontsize_formats: '11px 12px 14px 16px 18px 24px 36px 48px',
        link_title: false,
        branding: false,
        placeholder: this.placeholder,
        init_instance_callback: editor => {
          if (this.value) {
            this.resetContent(this.value);
            this.initFlag = true;
          }
          if (this.maxLength) {
            let statusbar = this.$refs.tinymceBox.querySelector('.mce-statusbar');
            if (statusbar) statusbar.appendChild(this.$refs.limit);
          }
          {
            let editArea = this.$refs.tinymceBox.querySelector('.mce-edit-area');
            if (editArea) editArea.appendChild(this.$refs.placeholder);
          }
          {
            this.setDisabled();
          }
          {
            this.resetIFrameStyle();
          }
          let content = '';
          editor.on('input change undo redo', () => {
            this.initFlag = true;
            if (this.maxLength && !this.checkWordLength()) {
              this.resetContent(content);
              return;
            }
            content = editor.getContent();
            this.$emit('input', content);
            this.currentLength = this.getWordLength();
          });
          editor.formatter.register({
            lineheight: {
              selector: 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li,table',
              styles: {'line-height': '%value'}
            }
          });
          this.$emit('init', editor);
        },
        setup: editor => {
          editor.on('paste', (e) => {
            let files = e.clipboardData.files;
            if (files.length) {
              if (!this.checkImg(files[0])) return;
              this.uploadImg(files[0]);
            }
          });
          editor.on('drop', (e) => {
            // console.log(e);
            let files = e.dataTransfer.files;
            if (files.length) {
              if (!this.checkImg(files[0])) return;
              this.uploadImg(files[0]);
            }
          });
          editor.on('dragover', (e) => {
            e.preventDefault();
          });
          // 定义按钮
          editor.addButton('insertimg', {
            // text: 'button',
            icon: 'image',
            tooltip: '插入图片',
            onclick: () => {
              this.$refs.file.click();
            }
          });
          const getLineHeightMenu = () => {
            let lineHeightVal = '1 1.1 1.2 1.3 1.4 1.5 1.75 2 3 4 5';
            return lineHeightVal.split(' ').map(v => ({
              text: v,
              detail: v,
              onclick: e => {
                editor.formatter.apply('lineheight', {value: +e.target.innerText});
                this.$emit('input', editor.getContent());
              }
            }));
          };
          editor.addButton('lineheight', {
            type: 'menubutton',
            icon: 'menu',
            tooltip: '行高',
            menu: getLineHeightMenu()
          });
          this.$emit('setup', editor);
        }
      });
    },
    resetIFrameStyle() {
      let iframe = this.$refs.tinymceBox.querySelector('iframe');
      let head = iframe.contentDocument.head;
      let style = document.createElement('style');
      style.innerHTML = `*{margin:0;padding:0;} body{padding:10px} img{vertical-align:top}`;
      head.appendChild(style);
    },
    destroyTinymce() {
      try {
        this.tinymce.destroy();
      } catch (e) {
        console.warn(e);
      }
    }
  }
};
</script>
<style scoped>
.tinymce-box {
  position: relative;
  overflow: hidden;
}

.placeholder {
  color: #999;
  pointer-events: none;
  position: absolute;
  top: 0;
  left: 0;
  text-indent: 10px;
  margin-top: 10px;
  line-height: normal;
}

.tips {
  position: absolute;
  top: 4px;
  right: 10px;
}

.limit {
  color: #999;
  font-size: 12px;
  position: absolute;
  bottom: 0;
  right: 10px;
  line-height: 30px;
}
</style>
<style>
.mce-fullscreen {
  z-index: 10000 !important;
}

.mce-tinymce.mce-container {
  box-sizing: border-box;
}

.mce-toolbar .mce-btn-group > div {
  white-space: normal;
  max-width: 640px;
}


.tinymce-box .mce-edit-area {
  position: relative;
}

.tinymce-box.disabled .mce-top-part::before {
  pointer-events: auto;
  z-index: 2;
}
</style>
